﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace H.Utils
{
    public static class EncryptUtil
    {

        private class XorStream : Stream
        {
            /// <summary>
            /// 内部管理的流
            /// </summary>
            private readonly Stream _Stream;

            /// <summary>
            /// 
            /// </summary>
            private readonly byte _Key;

            public override bool CanRead => _Stream.CanRead;

            public override bool CanSeek => _Stream.CanSeek;

            public override bool CanWrite => _Stream.CanWrite;

            public override long Length => _Stream.Length;

            public override long Position { get => _Stream.Position; set => _Stream.Position = value; }

            public XorStream(Stream src, byte key)
            {
                _Stream = src;
                _Key = key;
            }

            public override void Flush()
            {
                _Stream.Flush();
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                int ret = _Stream.Read(buffer, offset, count);
                for (int i = 0; i < ret; i++)
                {
                    buffer[offset + i] ^= _Key;
                }
                return ret;
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                return _Stream.Seek(offset, origin);
            }

            public override void SetLength(long value)
            {
                _Stream.SetLength(value);
            }
            private byte[] _Buffer = new byte[100];

            public override void Write(byte[] buffer, int offset, int count)
            {
                if (_Buffer.Length < count)
                {
                    _Buffer = new byte[count];
                }
                for (int i = 0; i < count; i++)
                {
                    _Buffer[i] = (byte)(buffer[offset + i] ^ _Key);
                }
                _Stream.Write(_Buffer, 0, count);
            }
        }

        /// <summary>
        /// 为流进行简单加密/解密
        /// </summary>
        /// <param name="srcStream"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static Stream StreamXor(this Stream srcStream, byte key)
        {
            return new XorStream(srcStream, key);
        }

        /// <summary>
        /// 为流进行加密
        /// </summary>
        /// <param name="srcStream"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static Stream Encrypt(this Stream srcStream, byte[] key, byte[] iv)
        {
            return new CryptoStream(srcStream, new DESCryptoServiceProvider().CreateEncryptor(key, iv), CryptoStreamMode.Write);
        }

        /// <summary>
        /// 为流进行解密
        /// </summary>
        /// <param name="srcStream"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static Stream Decrypt(this Stream srcStream, byte[] key, byte[] iv)
        {
            return new CryptoStream(srcStream, new DESCryptoServiceProvider().CreateDecryptor(key, iv), CryptoStreamMode.Read);
        }

        public static void GenKey(out byte[] key, out byte[] iv)
        {
            Random random = new Random();
            key = new byte[8];
            iv = new byte[8];
            random.NextBytes(key);
            random.NextBytes(iv);
        }
    }
}
